package _07剪邮票.拓展_连通性检测;


import java.util.Scanner;

/**
 * 给定一个方阵，定义连通；上下左右相邻，并且值相同
 * 可以想象成一张地图，不同的区域被涂上不同颜色
 * 输入：
 * 整数N，（N<50）表示矩阵的行列数
 * 接下来N行，每行N个字符，代表方阵中的元素
 * 接下来一个整数M，（M<1000）表示询问数
 * 接下来M行，每行代表一个询问
 * 格式为4个整数，y1,x1,y2,x2
 * 表示询问（第y1行，第x1列）与（第y2行，第x2列）是否连通
 * 连通输出true，否则false
 * <p>
 * 例如输入
 * 10
 * 0010000000
 * 0011100000
 * 0000111110
 * 0001100010
 * 1111010010
 * 0000010010
 * 0000010011
 * 0111111000
 * 0000010000
 * 0000000000
 * 3
 * 0 0 9 9
 * 0 2 6 8
 * 4 4 4 6
 * <p>
 * 输出
 * false
 * true
 * true
 */

public class demo0 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        sc.nextLine();
        //生成方阵
        char[][] graph = new char[N][N];
        for (int i = 0; i < N; i++)
            graph[i] = sc.nextLine().toCharArray();
        int M = sc.nextInt();
        //询问
        int[][] request = new int[M][4];
        for (int i = 0; i < M; i++)
            for (int j = 0; j < 4; j++)
                request[i][j] = sc.nextInt();
        //M对起点和终点
        for (int i = 0; i < M; i++) {    //对每个起点和终点，检查是否连通
            boolean ok = check(graph, new int[N][N], request[i]);
            System.out.println(ok);
        }
    }

    /**
     * 检查连个坐标是否连通
     *
     * @param graph  方阵
     * @param label  标记方阵中的每个元素是否被访问过
     * @param points 起点和终点的坐标 x1 y1 x2 y2
     * @return
     */
    private static boolean check(char[][] graph, int[][] label, int[] points) {
        int x1 = points[0];
        int y1 = points[1];
        int x2 = points[2];
        int y2 = points[3];
        //递归的显性退出条件，起点和终点重合
        if (x1 == x2 && y1 == y2)
            return true;
        int value = graph[x1][y1];
        //四个方向的寻找结果,隐性退出条件
        //如果的哥方向都走不了，证明走到了死角
        boolean f1 = false;
        boolean f2 = false;
        boolean f3 = false;
        boolean f4 = false;

        /**
         * 遵循以下访问顺序：左--右--上--下
         *
         *
         * 不管是在那个方向，能探索下一步的条件都是这三个
         * 1）下一步没有越界
         * 2）下一步和这一步同色（值相同）
         * 3）下一步没有被访问过
         */

        //往左走
        if (x1 - 1 >= 0 && label[x1 - 1][y1] == 0 && graph[x1 - 1][y1] == value) {
            label[x1 - 1][y1] = 1;//把左边的点标记为已访问
            points[0] = x1 - 1;//把左边的点标记为新的点，递归
            f1 = check(graph, label, points);
            //回溯,必须重置标记位
            label[x1 - 1][y1] = 0;
            points[0] = x1;
        }

        //往右走
        if (x1 + 1 < graph.length && label[x1 + 1][y1] == 0 && graph[x1 + 1][y1] == value) {
            label[x1 + 1][y1] = 1;
            points[0] = x1 + 1;
            f2 = check(graph, label, points);
            //回溯,必须重置标记位
            label[x1 + 1][y1] = 0;
            points[0] = x1;
        }

        //往上走
        if (y1 - 1 >= 0 && label[x1][y1 - 1] == 0 && graph[x1][y1 - 1] == value) {
            label[x1][y1 - 1] = 1;
            points[1] = y1 - 1;
            f3 = check(graph, label, points);
            //回溯,必须重置标记位
            label[x1][y1 - 1] = 0;
            points[1] = y1;
        }

        //往下走
        if (y1 + 1 < graph.length && label[x1][y1 + 1] == 0 && graph[x1][y1 + 1] == value) {
            label[x1][y1 + 1] = 1;
            points[1] = y1 + 1;
            f4 = check(graph, label, points);
            //回溯,必须重置标记位
            label[x1][y1 + 1] = 0;
            points[1] = y1;
        }

        //有任意一个方向成功找到，即为成功
        return f1 || f2 || f3 || f4;
    }


}
